home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 5 / QRZ Ham Radio Callsign Database - Volume 5.iso / files / tcpip / amiga / rhinosrc.lha / ftpserv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-01  |  14.9 KB  |  660 lines

  1. /* Internet FTP Server
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include <stdio.h>
  5. #include <ctype.h>
  6. #include <time.h>
  7. #ifdef    __TURBOC__
  8. #include <io.h>
  9. #include <dir.h>
  10. #endif
  11. #include "global.h"
  12. #include "mbuf.h"
  13. #include "proc.h"
  14. #include "socket.h"
  15. #include "dirutil.h"
  16. #include "commands.h"
  17. #include "files.h"
  18. #include "ftp.h"
  19. #include "ftpserv.h"
  20. #include "hardware.h"
  21.  
  22. static void ftpserv __ARGS((int s,void *unused,void *p));
  23. static int pport __ARGS((struct sockaddr_in *sock,char *arg));
  24. static void ftplogin __ARGS((struct ftpserv *ftp,char *pass));
  25. static int sendit __ARGS((struct ftpserv *ftp,char *command,char *file));
  26. static int recvit __ARGS((struct ftpserv *ftp,char *command,char *file));
  27.  
  28. /* Command table */
  29. static char *commands[] = {
  30.     "user",
  31.     "acct",
  32.     "pass",
  33.     "type",
  34.     "list",
  35.     "cwd",
  36.     "dele",
  37.     "name",
  38.     "quit",
  39.     "retr",
  40.     "stor",
  41.     "port",
  42.     "nlst",
  43.     "pwd",
  44.     "xpwd",            /* For compatibility with 4.2BSD */
  45.     "mkd ",
  46.     "xmkd",            /* For compatibility with 4.2BSD */
  47.     "xrmd",            /* For compatibility with 4.2BSD */
  48.     "rmd ",
  49.     "stru",
  50.     "mode",
  51.     NULLCHAR
  52. };
  53.  
  54. /* Response messages */
  55. static char banner[] = "220 %s FTP version %s ready at %s\n";
  56. static char badcmd[] = "500 Unknown command\n";
  57. static char binwarn[] = "100 Warning: type is ASCII and %s appears to be binary\n";
  58. static char unsupp[] = "500 Unsupported command or option\n";
  59. static char givepass[] = "331 Enter PASS command\n";
  60. static char logged[] = "230 Logged in\n";
  61. static char typeok[] = "200 Type %s OK\n";
  62. static char only8[] = "501 Only logical bytesize 8 supported\n";
  63. static char deleok[] = "250 File deleted\n";
  64. static char mkdok[] = "200 MKD ok\n";
  65. static char delefail[] = "550 Delete failed: %s\n";
  66. static char pwdmsg[] = "257 \"%s\" is current directory\n";
  67. static char badtype[] = "501 Unknown type \"%s\"\n";
  68. static char badport[] = "501 Bad port syntax\n";
  69. static char unimp[] = "502 Command not yet implemented\n";
  70. static char bye[] = "221 Goodbye!\n";
  71. static char nodir[] = "553 Can't read directory \"%s\": %s\n";
  72. static char cantopen[] = "550 Can't read file \"%s\": %s\n";
  73. static char sending[] = "150 Opening data connection for %s %s\n";
  74. static char cantmake[] = "553 Can't create \"%s\": %s\n";
  75. static char writerr[] = "552 Write error: %s\n";
  76. static char portok[] = "200 Port command okay\n";
  77. static char rxok[] = "226 File received OK\n";
  78. static char txok[] = "226 File sent OK\n";
  79. static char noperm[] = "550 Permission denied\n";
  80. static char noconn[] = "425 Data connection reset\n";
  81. static char lowmem[] = "421 System overloaded, try again later\n";
  82. static char notlog[] = "530 Please log in with USER and PASS\n";
  83. static char userfirst[] = "503 Login with USER first.\n";
  84. static char okay[] = "200 Ok\n";
  85.  
  86. static int Sftp = -1;    /* Prototype socket for service */
  87.  
  88. /* Start up FTP service */
  89. int
  90. ftpstart(argc,argv,p)
  91. int argc;
  92. char *argv[];
  93. void *p;
  94. {
  95.     struct sockaddr_in lsocket;
  96.     int s;
  97.     FILE *network;
  98.  
  99.     if(Sftp != -1){
  100.         /* Already running! */
  101.         return 0;
  102.     }
  103.     psignal(Curproc,0);    /* Don't keep the parser waiting */
  104.     chname(Curproc,"FTP listener");
  105.  
  106.     lsocket.sin_family = AF_INET;
  107.     lsocket.sin_addr.s_addr = INADDR_ANY;
  108.     if(argc < 2)
  109.         lsocket.sin_port = IPPORT_FTP;
  110.     else
  111.         lsocket.sin_port = atoi(argv[1]);
  112.  
  113.     Sftp = socket(AF_INET,SOCK_STREAM,0);
  114.     bind(Sftp,(char *)&lsocket,sizeof(lsocket));
  115.     listen(Sftp,1);
  116.     for(;;){
  117.         if((s = accept(Sftp,NULLCHAR,(int *)NULL)) == -1)
  118.             break;    /* Service is shutting down */
  119.  
  120.         network = fdopen(s,"r+t");
  121.         if(availmem() != 0){
  122.             fprintf(network,lowmem);
  123.             fclose(network);
  124.         } else {
  125.             /* Spawn a server */
  126.             newproc("ftpserv",2048,ftpserv,s,(void *)network,NULL,0);
  127.         }
  128.     }
  129.     return 0;
  130. }
  131. static void
  132. ftpserv(s,n,p)
  133. int s;    /* Socket with user connection */
  134. void *n;
  135. void *p;
  136. {
  137.     struct ftpserv ftp;
  138.     char **cmdp,buf[512],*arg,*cp,*cp1,*file,*mode;
  139.     long t;
  140.     int i;
  141.     struct sockaddr_in socket;
  142.  
  143.     memset((char *)&ftp,0,sizeof(ftp));    /* Start with clear slate */
  144.     ftp.control = (FILE *)n;
  145.     fclose(stdin);
  146.     stdin = fdup(ftp.control);
  147.     fclose(stdout);
  148.     stdout = fdup(ftp.control);
  149.  
  150.     sockowner(fileno(ftp.control),Curproc);        /* We own it now */
  151.     /* Set default data port */
  152.     i = SOCKSIZE;
  153.     getpeername(fileno(ftp.control),(char *)&socket,&i);
  154.     socket.sin_port = IPPORT_FTPD;
  155.     ASSIGN(ftp.port,socket);
  156.  
  157.     log(fileno(ftp.control),"open FTP");
  158.     time(&t);
  159.     cp = ctime(&t);
  160.     if((cp1 = strchr(cp,'\n')) != NULLCHAR)
  161.         *cp1 = '\0';
  162.     fprintf(ftp.control,banner,Hostname,Version,cp);
  163. loop:    fflush(ftp.control);
  164.     if((fgets(buf,sizeof(buf),ftp.control)) == NULLCHAR){
  165.         /* He closed on us */
  166.         goto finish;
  167.     }
  168.     if(strlen(buf) == 0){
  169.         /* Can't be a legal FTP command */
  170.         fprintf(ftp.control,badcmd);
  171.         goto loop;
  172.     }    
  173.     rip(buf);
  174. #ifdef    UNIX
  175.     /* Translate first word to lower case */
  176.     for(cp = buf;*cp != ' ' && *cp != '\0';cp++)
  177.         *cp = tolower(*cp);
  178. #else
  179.     /* Translate entire buffer to lower case */
  180.     for(cp = buf;*cp != '\0';cp++)
  181.         *cp = tolower(*cp);
  182. #endif
  183.     /* Find command in table; if not present, return syntax error */
  184.     for(cmdp = commands;*cmdp != NULLCHAR;cmdp++)
  185.         if(strncmp(*cmdp,buf,strlen(*cmdp)) == 0)
  186.             break;
  187.     if(*cmdp == NULLCHAR){
  188.         fprintf(ftp.control,badcmd);
  189.         goto loop;
  190.     }
  191.     /* Allow only USER, PASS and QUIT before logging in */
  192.     if(ftp.cd == NULLCHAR || ftp.path == NULLCHAR){
  193.         switch(cmdp-commands){
  194.         case USER_CMD:
  195.         case PASS_CMD:
  196.         case QUIT_CMD:
  197.             break;
  198.         default:
  199.             fprintf(ftp.control,notlog);
  200.             goto loop;
  201.         }
  202.     }
  203.     arg = &buf[strlen(*cmdp)];
  204.     while(*arg == ' ')
  205.         arg++;
  206.  
  207.     /* Execute specific command */
  208.     switch(cmdp-commands){
  209.     case USER_CMD:
  210.         free(ftp.username);
  211.         ftp.username = strdup(arg);
  212.         fprintf(ftp.control,givepass);
  213.         break;
  214.     case TYPE_CMD:
  215.         switch(arg[0]){
  216.         case 'A':
  217.         case 'a':    /* Ascii */
  218.             ftp.type = ASCII_TYPE;
  219.             fprintf(ftp.control,typeok,arg);
  220.             break;
  221.         case 'l':
  222.         case 'L':
  223.             while(*arg != ' ' && *arg != '\0')
  224.                 arg++;
  225.             if(*arg == '\0' || *++arg != '8'){
  226.                 fprintf(ftp.control,only8);
  227.                 break;
  228.             }
  229.             ftp.type = LOGICAL_TYPE;
  230.             ftp.logbsize = 8;
  231.             fprintf(ftp.control,typeok,arg);
  232.             break;
  233.         case 'B':
  234.         case 'b':    /* Binary */
  235.         case 'I':
  236.         case 'i':    /* Image */
  237.             ftp.type = IMAGE_TYPE;
  238.             fprintf(ftp.control,typeok,arg);
  239.             break;
  240.         default:    /* Invalid */
  241.             fprintf(ftp.control,badtype,arg);
  242.             break;
  243.         }
  244.         break;
  245.     case QUIT_CMD:
  246.         fprintf(ftp.control,bye);
  247.         goto finish;
  248.     case RETR_CMD:
  249.         file = pathname(ftp.cd,arg);
  250.         switch(ftp.type){
  251.         case IMAGE_TYPE:
  252.         case LOGICAL_TYPE:
  253.             mode = READ_BINARY;
  254.             break;
  255.         case ASCII_TYPE:
  256.             mode = READ_TEXT;
  257.             break;
  258.         }
  259.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  260.              fprintf(ftp.control,noperm);
  261.         } else if((ftp.fp = fopen(file,mode)) == NULLFILE){
  262.             fprintf(ftp.control,cantopen,file,sys_errlist[errno]);
  263.         } else {
  264.             log(fileno(ftp.control),"RETR %s",file);
  265.             if(ftp.type == ASCII_TYPE && isbinary(ftp.fp)){
  266.                 fprintf(ftp.control,binwarn,file);
  267.             }
  268.             sendit(&ftp,"RETR",file);
  269.         }
  270.         free(file);
  271.         break;
  272.     case STOR_CMD:
  273.         file = pathname(ftp.cd,arg);
  274.         switch(ftp.type){
  275.         case IMAGE_TYPE:
  276.         case LOGICAL_TYPE:
  277.             mode = WRITE_BINARY;
  278.             break;
  279.         case ASCII_TYPE:
  280.             mode = WRITE_TEXT;
  281.             break;
  282.         }
  283.         if(!permcheck(ftp.path,ftp.perms,STOR_CMD,file)){
  284.              fprintf(ftp.control,noperm);
  285.         } else if((ftp.fp = fopen(file,mode)) == NULLFILE){
  286.             fprintf(ftp.control,cantmake,file,sys_errlist[errno]);
  287.         } else {
  288.             log(fileno(ftp.control),"STOR %s",file);
  289.             recvit(&ftp,"STOR",file);
  290.         }
  291.         free(file);
  292.         break;
  293.     case PORT_CMD:
  294.         if(pport(&ftp.port,arg) == -1){
  295.             fprintf(ftp.control,badport);
  296.         } else {
  297.             fprintf(ftp.control,portok);
  298.         }
  299.         break;
  300. #ifndef CPM
  301.     case LIST_CMD:
  302.         file = pathname(ftp.cd,arg);
  303.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  304.              fprintf(ftp.control,noperm);
  305.         } else if((ftp.fp = dir(file,1)) == NULLFILE){
  306.             fprintf(ftp.control,nodir,file,sys_errlist[errno]);
  307.         } else {
  308.             sendit(&ftp,"LIST",file);
  309.         }
  310.         free(file);
  311.         break;
  312.     case NLST_CMD:
  313.         file = pathname(ftp.cd,arg);
  314.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  315.              fprintf(ftp.control,noperm);
  316.         } else if((ftp.fp = dir(file,0)) == NULLFILE){
  317.             fprintf(ftp.control,nodir,file,sys_errlist[errno]);
  318.         } else {
  319.             sendit(&ftp,"NLST",file);
  320.         }
  321.         free(file);
  322.         break;
  323.     case CWD_CMD:
  324.         file = pathname(ftp.cd,arg);
  325.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  326.              fprintf(ftp.control,noperm);
  327.             free(file);
  328. #ifdef    MSDOS
  329.         /* Don'tcha just LOVE %%$#@!! MS-DOS? */
  330.         } else if(strcmp(file,"/") == 0 || access(file,0) == 0){
  331. #else
  332.         } else if(access(file,0) == 0){    /* See if it exists */
  333. #endif
  334.             /* Succeeded, record in control block */
  335.             free(ftp.cd);
  336.             ftp.cd = file;
  337.             fprintf(ftp.control,pwdmsg,file);
  338.         } else {
  339.             /* Failed, don't change anything */
  340.             fprintf(ftp.control,nodir,file,sys_errlist[errno]);
  341.             free(file);
  342.         }
  343.         break;
  344.     case XPWD_CMD:
  345.     case PWD_CMD:
  346.         fprintf(ftp.control,pwdmsg,ftp.cd);
  347.         break;
  348. #else
  349.     case LIST_CMD:
  350.     case NLST_CMD:
  351.     case CWD_CMD:
  352.     case XPWD_CMD:
  353.     case PWD_CMD:
  354. #endif
  355.     case ACCT_CMD:        
  356.         fprintf(ftp.control,unimp);
  357.         break;
  358.     case DELE_CMD:
  359.         file = pathname(ftp.cd,arg);
  360.         if(!permcheck(ftp.path,ftp.perms,DELE_CMD,file)){
  361.              fprintf(ftp.control,noperm);
  362.         } else if(unlink(file) == 0){
  363.             log(fileno(ftp.control),"DELE %s",file);
  364.             fprintf(ftp.control,deleok);
  365.         } else {
  366.             fprintf(ftp.control,delefail,sys_errlist[errno]);
  367.         }
  368.         free(file);
  369.         break;
  370.     case PASS_CMD:
  371.         if(ftp.username == NULLCHAR)
  372.             fprintf(ftp.control,userfirst);
  373.         else
  374.             ftplogin(&ftp,arg);            
  375.         break;
  376. #ifndef    CPM
  377.     case XMKD_CMD:
  378.     case MKD_CMD:
  379.         file = pathname(ftp.cd,arg);
  380.         if(!permcheck(ftp.path,ftp.perms,MKD_CMD,file)){
  381.             fprintf(ftp.control,noperm);
  382. #ifdef    UNIX
  383.         } else if(mkdir(file,0777) == 0){
  384. #else
  385.         } else if(mkdir(file) == 0){
  386. #endif
  387.             log(fileno(ftp.control),"MKD %s",file);
  388.             fprintf(ftp.control,mkdok);
  389.         } else {
  390.             fprintf(ftp.control,cantmake,file,sys_errlist[errno]);
  391.         }
  392.         free(file);
  393.         break;
  394.     case XRMD_CMD:
  395.     case RMD_CMD:
  396.         file = pathname(ftp.cd,arg);
  397.         if(!permcheck(ftp.path,ftp.perms,RMD_CMD,file)){
  398.              fprintf(ftp.control,noperm);
  399.         } else if(rmdir(file) == 0){
  400.             log(fileno(ftp.control),"RMD %s",file);
  401.             fprintf(ftp.control,deleok);
  402.         } else {
  403.             fprintf(ftp.control,delefail,sys_errlist[errno]);
  404.         }
  405.         free(file);
  406.         break;
  407.     case STRU_CMD:
  408.         if(tolower(arg[0]) != 'f')
  409.             fprintf(ftp.control,unsupp);
  410.         else
  411.             fprintf(ftp.control,okay);
  412.         break;
  413.     case MODE_CMD:
  414.         if(tolower(arg[0]) != 's')
  415.             fprintf(ftp.control,unsupp);
  416.         else
  417.             fprintf(ftp.control,okay);
  418.         break;
  419.     }
  420. #endif
  421.     goto loop;
  422. finish:
  423.     log(fileno(ftp.control),"close FTP");
  424.     /* Clean up */
  425.     fclose(ftp.control);
  426.     if(ftp.data != NULLFILE)
  427.         fclose(ftp.data);
  428.     if(ftp.fp != NULLFILE)
  429.         fclose(ftp.fp);
  430.     free(ftp.username);
  431.     free(ftp.path);
  432.     free(ftp.cd);
  433. }
  434.  
  435. /* Shut down FTP server */
  436. int
  437. ftp0(argc,argv,p)
  438. int argc;
  439. char *argv[];
  440. void *p;
  441. {
  442.     close_s(Sftp);
  443.     Sftp = -1;
  444.     return 0;
  445. }
  446. static
  447. int
  448. pport(sock,arg)
  449. struct sockaddr_in *sock;
  450. char *arg;
  451. {
  452.     int32 n;
  453.     int i;
  454.  
  455.     n = 0;
  456.     for(i=0;i<4;i++){
  457.         n = atoi(arg) + (n << 8);
  458.         if((arg = strchr(arg,',')) == NULLCHAR)
  459.             return -1;
  460.         arg++;
  461.     }
  462.     sock->sin_addr.s_addr = n;
  463.     n = atoi(arg);
  464.     if((arg = strchr(arg,',')) == NULLCHAR)
  465.         return -1;
  466.     arg++;
  467.     n = atoi(arg) + (n << 8);
  468.     sock->sin_port = n;
  469.     return 0;
  470. }
  471.  
  472. /* Attempt to log in the user whose name is in ftp->username and password
  473.  * in pass
  474.  */
  475. static void
  476. ftplogin(ftp,pass)
  477. struct ftpserv *ftp;
  478. char *pass;
  479. {
  480.     char *path;
  481.     int anony = 0;
  482.  
  483.     path = mallocw(200);
  484.     if((ftp->perms = userlogin(ftp->username,pass,&path,200,&anony))
  485.        == -1){
  486.         fprintf(ftp->control,noperm);
  487.         free(path);
  488.         return;
  489.     }
  490.     /* Set up current directory and path prefix */
  491. #if    defined(AMIGAGONE)
  492.     ftp->cd = pathname("", path);
  493.     ftp->path = strdup(ftp->cd);
  494.     free(path);
  495. #else
  496.     ftp->cd = path;
  497.     ftp->path = strdup(path);
  498. #endif
  499.  
  500.     fprintf(ftp->control,logged);
  501.     if(!anony)
  502.         log(fileno(ftp->control),"%s logged in",ftp->username);
  503.     else
  504.         log(fileno(ftp->control),"%s logged in, ID %s",ftp->username,pass);
  505. }
  506.  
  507. #ifdef    MSDOS
  508. /* Illegal characters in a DOS filename */
  509. static char badchars[] = "\"[]:|<>+=;,";
  510. #endif
  511.  
  512. /* Return 1 if the file operation is allowed, 0 otherwise */
  513. int
  514. permcheck(path,perms,op,file)
  515. char *path;
  516. int perms;
  517. int op;
  518. char *file;
  519. {
  520. #ifdef    MSDOS
  521.     char *cp;
  522. #endif
  523.  
  524.     if(file == NULLCHAR || path == NULLCHAR)
  525.         return 0;    /* Probably hasn't logged in yet */
  526. #ifdef    MSDOS
  527.     /* Check for characters illegal in MS-DOS file names */
  528.     for(cp = badchars;*cp != '\0';cp++){
  529.         if(strchr(file,*cp) != NULLCHAR)
  530.             return 0;    
  531.     }
  532. #endif
  533. #ifndef MAC
  534.     /* The target file must be under the user's allowed search path */
  535.     if(strncmp(file,path,strlen(path)) != 0)
  536.         return 0;
  537. #endif
  538.  
  539.     switch(op){
  540.     case RETR_CMD:
  541.         /* User must have permission to read files */
  542.         if(perms & FTP_READ)
  543.             return 1;
  544.         return 0;
  545.     case DELE_CMD:
  546.     case RMD_CMD:
  547.         /* User must have permission to (over)write files */
  548.         if(perms & FTP_WRITE)
  549.             return 1;
  550.         return 0;
  551.     case STOR_CMD:
  552.     case MKD_CMD:
  553.         /* User must have permission to (over)write files, or permission
  554.          * to create them if the file doesn't already exist
  555.          */
  556.         if(perms & FTP_WRITE)
  557.             return 1;
  558.         if(access(file,2) == -1 && (perms & FTP_CREATE))
  559.             return 1;
  560.         return 0;
  561.     }
  562.     return 0;    /* "can't happen" -- keep lint happy */
  563. }
  564. static int
  565. sendit(ftp,command,file)
  566. struct ftpserv *ftp;
  567. char *command;
  568. char *file;
  569. {
  570.     long total;
  571.     struct sockaddr_in dport;
  572.     int s;
  573.  
  574.     s = socket(AF_INET,SOCK_STREAM,0);
  575.     dport.sin_family = AF_INET;
  576.     dport.sin_addr.s_addr = INADDR_ANY;
  577.     dport.sin_port = IPPORT_FTPD;
  578.     bind(s,(char *)&dport,SOCKSIZE);
  579.     fprintf(ftp->control,sending,command,file);
  580.     fflush(ftp->control);
  581.     if(connect(s,(char *)&ftp->port,SOCKSIZE) == -1){
  582.         fclose(ftp->fp);
  583.         ftp->fp = NULLFILE;
  584.         close_s(s);
  585.         ftp->data = NULLFILE;
  586.         fprintf(ftp->control,noconn);
  587.         return -1;
  588.     }
  589.     ftp->data = fdopen(s,"r+");
  590.     /* Do the actual transfer */
  591.     total = sendfile(ftp->fp,ftp->data,ftp->type,0);
  592.  
  593.     if(total == -1){
  594.         /* An error occurred on the data connection */
  595.         fprintf(ftp->control,noconn);
  596.         shutdown(fileno(ftp->data),2);    /* Blow away data connection */
  597.         fclose(ftp->data);
  598.     } else {
  599.         fprintf(ftp->control,txok);
  600.     }
  601.     fclose(ftp->fp);
  602.     ftp->fp = NULLFILE;
  603.     fclose(ftp->data);
  604.     ftp->data = NULLFILE;
  605.     if(total == -1)
  606.         return -1;
  607.     else
  608.         return 0;
  609. }
  610. static int
  611. recvit(ftp,command,file)
  612. struct ftpserv *ftp;
  613. char *command;
  614. char *file;
  615. {
  616.     struct sockaddr_in dport;
  617.     long total;
  618.     int s;
  619.  
  620.     s = socket(AF_INET,SOCK_STREAM,0);
  621.     dport.sin_family = AF_INET;
  622.     dport.sin_addr.s_addr = INADDR_ANY;
  623.     dport.sin_port = IPPORT_FTPD;
  624.     bind(s,(char *)&dport,SOCKSIZE);
  625.     fprintf(ftp->control,sending,command,file);
  626.     fflush(ftp->control);
  627.     if(connect(s,(char *)&ftp->port,SOCKSIZE) == -1){
  628.         fclose(ftp->fp);
  629.         ftp->fp = NULLFILE;
  630.         close_s(s);
  631.         ftp->data = NULLCHAR;
  632.         fprintf(ftp->control,noconn);
  633.         return -1;
  634.     }
  635.     ftp->data = fdopen(s,"r+");
  636.     /* Do the actual transfer */
  637.     total = recvfile(ftp->fp,ftp->data,ftp->type,0);
  638.  
  639. #ifdef    CPM
  640.     if(ftp->type == ASCII_TYPE)
  641.         putc(CTLZ,ftp->fp);
  642. #endif
  643.     if(total == -1) {
  644.         /* An error occurred while writing the file */
  645.         fprintf(ftp->control,writerr,sys_errlist[errno]);
  646.         shutdown(fileno(ftp->data),2);    /* Blow it away */
  647.         fclose(ftp->data);
  648.     } else {
  649.         fprintf(ftp->control,rxok);
  650.         fclose(ftp->data);
  651.     }
  652.     ftp->data = NULLFILE;
  653.     fclose(ftp->fp);
  654.     ftp->fp = NULLFILE;
  655.     if(total == -1)
  656.         return -1;
  657.     else
  658.         return 0;
  659. }
  660.